package com.his.aop;

import com.his.annotation.RequireRoles;
import com.his.common.Const;
import com.his.entity.HisUser;
import com.his.entity.Log;
import com.his.entity.Patient;
import com.his.mapper.LogMapper;
import com.his.utils.JWTUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 控制层日志打印
 *
 * @author dawn
 */
@Aspect
@Slf4j
@Component
@Order(1)
public class ControllerLog {
    private final List<String> asList;

    private ControllerLog() {
        String[] write = {"/schedule/getSchedule", "/log/getAll","order/payQuery"};
        asList = Arrays.asList(write);
    }

    @Resource
    private LogMapper logMapper;

    @Pointcut("execution(* *.*.controller.*.*(..))")
    public void controller() {
    }

    /**
     * 记录日志的切面
     *
     * @param joinPoint 切面连接点参数
     * @return 返回方法的执行结果
     */
    @Around("controller()")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Objects.requireNonNull(requestAttributes).getRequest();
        Object result = joinPoint.proceed();
        String uri = request.getRequestURI();
        String ip = request.getRemoteAddr();
        //创建线程进行日志数据插入工作
        new Thread(() -> {
            //请求如果在白名单就不进行数据库的插入
            if (asList.contains(uri)) {
                return;
            }
            //拿到接口的参数
            Object[] args = joinPoint.getArgs();
            //获取方法签名
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            //获取注解
            RequireRoles annotation = method.getAnnotation(RequireRoles.class);
            if (annotation == null) {
                return;
            }
            //操作人姓名
            String name = "";
            int index = -1;
            //拿到token的位置,解析token拿到token中的姓名
            try {
                index = annotation.index();
                Object o = JWTUtil.parserToken(args[index].toString(), Const.PUBLIC_KEY);
                if (o instanceof HisUser) {
                    name = ((HisUser) o).getRealName();
                } else {
                    name = ((Patient) o).getRealName();
                }
            } catch (Exception e) {
                log.error("生成日志的时候token解析异常");
            }
            //获取用户的请求数据
            StringBuilder requestData = new StringBuilder();
            for (int i = 0; i < args.length; i++) {
                if (i == index) {
                    continue;
                }
                requestData.append("<h4>参数").append(i).append("</h4><p>").append(args[i]).append("</p>");
            }
            //插入数据库中
            Log log = new Log(name, ip, new Date(), uri, requestData.toString());
            logMapper.add(log);
        }).start();
        return result;
    }
}
